package cn.npe.di.aop;


import cn.npe.di.annotation.DI;
import cn.npe.di.handler.InvokeHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;

public class InvokeProxy {

    public static Object newProxy(Field field, ApplicationContext context) {
        return Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class[]{field.getType()}, new InvokeAdvice(field, context));
    }

    public static Object newProxy(Method methodElement,Class<?> type, ApplicationContext context) {
        return Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class[]{type}, new InvokeAdvice(methodElement, type,context));
    }

    private static class InvokeAdvice implements InvocationHandler {

        private Field field;


        private Method methodElement;

        private Class<?> type;

        private ApplicationContext context;

        public InvokeAdvice(Field field, ApplicationContext context) {
            this.field = field;
            this.context = context;
        }

        public InvokeAdvice(Method method,Class<?> type, ApplicationContext context) {
            this.methodElement = method;
            this.context = context;
            this.type=type;
        }

        //代理对象被调用时
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Map<String, InvokeHandler> beansofType = context.getBeansOfType(InvokeHandler.class);
            AnnotationAttributes attributes=null;
            if (this.field != null) {
                 attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(field, DI.class);
            } else if (this.methodElement != null) {
                 attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(methodElement, DI.class);
            }
            if(attributes!=null) {
                String value = attributes.getString("value");
                String[] serviceIds = attributes.getStringArray("serviceIds");
                for (Map.Entry<String, InvokeHandler> entry : beansofType.entrySet()) {
                    if (entry.getValue().support(value)) {
                        entry.getValue().invoke(proxy, method, args, field.getType(), serviceIds);
                    }
                }
            }
            return null;
        }
    }
}
